package online.hxstar.cloud.gateway.dynamic;

import com.alibaba.cloud.nacos.NacosConfigProperties;
import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.AbstractListener;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.extern.slf4j.Slf4j;
import online.hxstar.cloud.gateway.dynamic.model.GatewayFilterDefinition;
import online.hxstar.cloud.gateway.dynamic.model.GatewayPredicateDefinition;
import online.hxstar.cloud.gateway.dynamic.model.GatewayRouteDefinition;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;

/**
 * @author xinghu
 * @date 2019/9/6 12:45 下午
 */
@Component
@Slf4j
public class NacosRouteConfigListener {


	private final DynamicRouteService dynamicRouteService;
	@Value(value = "${gatewayRouter:spring-cloud-gateway-router}")
	private String gatewayRouter;
	@Value("${spring.cloud.nacos.config.group:DEFAULT_GROUP}")
	private String group;
	@Resource
	private NacosConfigProperties nacosConfigProperties;

	public NacosRouteConfigListener(
			DynamicRouteService dynamicRouteService) {
		this.dynamicRouteService = dynamicRouteService;
	}


	/**
	 * 监听Nacos Server下发的动态路由配置
	 */
	@PostConstruct
	private void initRouteByNacosListener() {
		try {
			ConfigService configService = nacosConfigProperties.configServiceInstance();
			String content = configService.getConfig(gatewayRouter, group, 5000);
			log.info("initRouteByNacosListener：：：{}", content);
			setRouteDefinition(content);
			configService.addListener(gatewayRouter, group, new AbstractListener() {
				@Override
				public void receiveConfigInfo(String configInfo) {
					log.info("configService.addListener\n{}", configInfo);
					setRouteDefinition(configInfo);
				}
			});
		} catch (NacosException e) {
			log.error("Nacos 配置异常。", e);
		}
	}

	private void setRouteDefinition(String content) {
		try {
			List<GatewayRouteDefinition> list = JSON.parseArray(content,
					GatewayRouteDefinition.class);
			log.info(list.toString());
			for (GatewayRouteDefinition definition : list) {
				RouteDefinition routeDefinition = assembleRouteDefinition(definition);
				//更新路由
				dynamicRouteService.update(routeDefinition);
				log.info("item--->{}", JSON.toJSONString(definition));
			}
		} catch (Exception e) {
			log.error("配置路由出错，，", e);
		}
	}

	/**
	 * 把获取到的的参数组装成路由对象
	 *
	 * @param routeDefinition 路由定义信息
	 * @return 路由信息
	 */
	private RouteDefinition assembleRouteDefinition(GatewayRouteDefinition routeDefinition) {
		RouteDefinition definition = new RouteDefinition();
		definition.setId(routeDefinition.getId());
		definition.setOrder(routeDefinition.getOrder());

		//设置断言
		List<PredicateDefinition> pdList = new ArrayList<>();
		List<GatewayPredicateDefinition> gatewayPredicateDefinitionList = routeDefinition
				.getPredicates();
		for (GatewayPredicateDefinition gpDefinition : gatewayPredicateDefinitionList) {
			PredicateDefinition predicate;
			if (gpDefinition.getArgs() == null) {
				predicate = new PredicateDefinition(gpDefinition.getName());

			} else {
				predicate = new PredicateDefinition();
				predicate.setArgs(gpDefinition.getArgs());
				predicate.setName(gpDefinition.getName());
			}
			pdList.add(predicate);
		}
		definition.setPredicates(pdList);

		//设置过滤器
		List<FilterDefinition> filters = new ArrayList<>();
		List<GatewayFilterDefinition> gatewayFilters = routeDefinition.getFilters();
		for (GatewayFilterDefinition filterDefinition : gatewayFilters) {
			FilterDefinition filter;
			if (filterDefinition.getArgs() == null) {
				filter = new FilterDefinition(filterDefinition.getName());
			} else {
				filter = new FilterDefinition();
				filter.setName(filterDefinition.getName());
				filter.setArgs(filterDefinition.getArgs());
			}
			filters.add(filter);
		}
		definition.setFilters(filters);
		URI uri;
		String http = "http";
		if (routeDefinition.getUri().startsWith(http)) {
			uri = UriComponentsBuilder.fromHttpUrl(routeDefinition.getUri()).build().toUri();
		} else {
			uri = URI.create(routeDefinition.getUri());
		}
		definition.setUri(uri);
		return definition;
	}
}
